package com.d3works.apps.bankpayment.service.invoice.payment;

import com.d3works.apps.account.db.Invoice;
import com.d3works.apps.account.db.InvoicePayment;
import com.d3works.apps.account.db.PaymentMode;
import com.d3works.apps.account.db.repo.InvoicePaymentRepository;
import com.d3works.apps.account.db.repo.PaymentModeRepository;
import com.d3works.apps.account.service.AccountManagementAccountService;
import com.d3works.apps.account.service.AccountingSituationService;
import com.d3works.apps.account.service.ReconcileService;
import com.d3works.apps.account.service.app.AppAccountService;
import com.d3works.apps.account.service.config.AccountConfigService;
import com.d3works.apps.account.service.invoice.InvoiceTermService;
import com.d3works.apps.account.service.move.MoveCreateService;
import com.d3works.apps.account.service.move.MoveToolService;
import com.d3works.apps.account.service.move.MoveValidateService;
import com.d3works.apps.account.service.moveline.MoveLineCreateService;
import com.d3works.apps.account.service.payment.PaymentModeService;
import com.d3works.apps.account.service.payment.invoice.payment.InvoicePaymentToolService;
import com.d3works.apps.account.service.payment.invoice.payment.InvoicePaymentValidateServiceImpl;
import com.d3works.apps.bankpayment.db.BankOrder;
import com.d3works.apps.bankpayment.exception.BankPaymentExceptionMessage;
import com.d3works.apps.bankpayment.service.bankorder.BankOrderCreateService;
import com.d3works.apps.bankpayment.service.bankorder.BankOrderService;
import com.d3works.apps.base.db.Company;
import com.d3works.exception.D3worksException;
import com.d3works.exception.db.repo.TraceBackRepository;
import com.d3works.i18n.I18n;
import com.d3works.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import com.google.inject.servlet.RequestScoped;
import java.io.IOException;
import javax.xml.bind.JAXBException;
import javax.xml.datatype.DatatypeConfigurationException;

@RequestScoped
public class InvoicePaymentValidateServiceBankPayImpl extends InvoicePaymentValidateServiceImpl {

  protected BankOrderCreateService bankOrderCreateService;
  protected BankOrderService bankOrderService;
  protected InvoiceTermService invoiceTermService;
  protected InvoicePaymentToolService invoicePaymentToolService;

  @Inject
  public InvoicePaymentValidateServiceBankPayImpl(
      PaymentModeService paymentModeService,
      MoveCreateService moveCreateService,
      MoveValidateService moveValidateService,
      MoveToolService moveToolService,
      MoveLineCreateService moveLineCreateService,
      AccountConfigService accountConfigService,
      InvoicePaymentRepository invoicePaymentRepository,
      ReconcileService reconcileService,
      InvoicePaymentToolService invoicePaymentToolService,
      InvoiceTermService invoiceTermService,
      AppAccountService appAccountService,
      AccountManagementAccountService accountManagementAccountService,
      BankOrderCreateService bankOrderCreateService,
      BankOrderService bankOrderService) {
    super(
        paymentModeService,
        moveCreateService,
        moveValidateService,
        moveToolService,
        moveLineCreateService,
        accountConfigService,
        invoicePaymentRepository,
        reconcileService,
        appAccountService,
        accountManagementAccountService);
    this.bankOrderCreateService = bankOrderCreateService;
    this.bankOrderService = bankOrderService;
    this.invoiceTermService = invoiceTermService;
    this.invoicePaymentToolService = invoicePaymentToolService;
  }

  @Override
  protected void setInvoicePaymentStatus(InvoicePayment invoicePayment) throws D3worksException {
    Invoice invoice = invoicePayment.getInvoice();
    PaymentMode paymentMode = invoicePayment.getPaymentMode();
    if (paymentMode == null) {
      throw new D3worksException(
          TraceBackRepository.CATEGORY_MISSING_FIELD,
          I18n.get(BankPaymentExceptionMessage.INVOICE_PAYMENT_MODE_MISSING),
          invoice.getInvoiceId());
    }

    if (paymentModeService.isPendingPayment(paymentMode)
        && paymentMode.getGenerateBankOrder()
        && paymentMode.getAccountingTriggerSelect()
            != PaymentModeRepository.ACCOUNTING_TRIGGER_IMMEDIATE
        && invoicePayment.getStatusSelect() == InvoicePaymentRepository.STATUS_DRAFT) {
      invoicePayment.setStatusSelect(InvoicePaymentRepository.STATUS_PENDING);
    } else {
      invoicePayment.setStatusSelect(InvoicePaymentRepository.STATUS_VALIDATED);
    }
  }

  @Override
  protected void createInvoicePaymentMove(InvoicePayment invoicePayment)
      throws D3worksException, JAXBException, IOException, DatatypeConfigurationException {
    Invoice invoice = invoicePayment.getInvoice();
    Company company = invoice.getCompany();

    PaymentMode paymentMode = invoicePayment.getPaymentMode();
    if (accountConfigService.getAccountConfig(company).getGenerateMoveForInvoicePayment()
        && (!paymentMode.getGenerateBankOrder()
            || paymentMode.getAccountingTriggerSelect()
                == PaymentModeRepository.ACCOUNTING_TRIGGER_IMMEDIATE)) {
      invoicePayment = this.createMoveForInvoicePayment(invoicePayment);
    } else {
      Beans.get(AccountingSituationService.class)
          .updateCustomerCredit(invoicePayment.getInvoice().getPartner());
      invoicePayment = invoicePaymentRepository.save(invoicePayment);
    }
    if (paymentMode.getGenerateBankOrder()
        && invoicePayment.getBankOrder() == null
        && invoicePayment.getPaymentSession() == null) {
      this.createBankOrder(invoicePayment);
    }
  }

  @Transactional(rollbackOn = {Exception.class})
  public void validateFromBankOrder(InvoicePayment invoicePayment, boolean force)
      throws D3worksException {

    invoicePayment.setStatusSelect(InvoicePaymentRepository.STATUS_VALIDATED);

    Company company = invoicePayment.getInvoice().getCompany();

    if (accountConfigService.getAccountConfig(company).getGenerateMoveForInvoicePayment()) {
      invoicePayment = this.createMoveForInvoicePayment(invoicePayment);
    } else {
      Beans.get(AccountingSituationService.class)
          .updateCustomerCredit(invoicePayment.getInvoice().getPartner());
      invoicePayment = invoicePaymentRepository.save(invoicePayment);
    }

    invoicePaymentToolService.updateAmountPaid(invoicePayment.getInvoice());
  }

  /**
   * Method to create a bank order for an invoice Payment
   *
   * @param invoicePayment An invoice payment
   * @throws D3worksException
   * @throws DatatypeConfigurationException
   * @throws IOException
   * @throws JAXBException
   */
  @Transactional(rollbackOn = {Exception.class})
  public void createBankOrder(InvoicePayment invoicePayment)
      throws D3worksException, JAXBException, IOException, DatatypeConfigurationException {

    BankOrder bankOrder = bankOrderCreateService.createBankOrder(invoicePayment);

    if (invoicePayment.getPaymentMode().getAutoConfirmBankOrder()) {
      bankOrderService.confirm(bankOrder);
    }
    invoicePayment.setBankOrder(bankOrder);

    invoicePaymentRepository.save(invoicePayment);
  }
}
